package com.itstyle.seckill.util;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.List;

/**
 * @author lifujun
 * @description:
 * @date 2024/3/6 14:51
 */
@Aspect
@Component
public class WebLogAspect {
    private static final Logger LOGGER = LoggerFactory.getLogger(WebLogAspect.class);
    private final ThreadLocal<Long> startTime = new ThreadLocal();
    private final ThreadLocal<String> logContent = new ThreadLocal();

    public WebLogAspect() {
    }

    @Pointcut("@annotation(com.itstyle.seckill.util.WebLog)")
    public void webLog() {
    }

    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) {
        this.startTime.set(System.currentTimeMillis());
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();
        WebLog webLog = (WebLog)method.getAnnotation(WebLog.class);
        String content = webLog.value();
        this.logContent.set(content);
        LOGGER.info("--------------> {} start <--------------", content);
        Parameter[] parameters = method.getParameters();
        List<Object> list = Lists.newArrayList();

        for(int i = 0; i < parameters.length; ++i) {
            Parameter p = parameters[i];
            if (!p.isAnnotationPresent(WebLogIgnore.class)) {
                Object o = joinPoint.getArgs()[i];
                if (o != null) {
                    list.add(o);
                }
            }
        }

        String url = request.getRequestURL().toString();
        String args = list.toString();
        LOGGER.info("URL : {}", url);
        LOGGER.info("HTTP_METHOD : {}", request.getMethod());
        LOGGER.info("IP : {}", request.getRemoteAddr());
        LOGGER.info("CLASS_METHOD : {}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        LOGGER.info("ARGS : {}", args);
    }

    @AfterReturning(
            returning = "ret",
            pointcut = "webLog()"
    )
    public void doAfterReturning(Object ret) {
        LOGGER.info("RESPONSE : {}", JSON.toJSON(ret));
        LOGGER.info("SPEND TIME : {}ms", System.currentTimeMillis() - (Long)this.startTime.get());
        this.cleanThreadLocal();
    }

    private void cleanThreadLocal() {
        LOGGER.info("--------------> {} end <--------------", this.logContent.get());
        this.startTime.remove();
        this.logContent.remove();
    }
}

